package net.neptech.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import net.neptech.mapper.WorkflowMapper;
import net.neptech.model.dto.CreateFlowDto;

import net.neptech.model.dto.NodeUser;
import net.neptech.model.dto.node.Node;
import net.neptech.model.dto.node.RootNode;
import net.neptech.model.workflow.Workflow;
import net.neptech.model.workflow.WorkflowForm;
import net.neptech.model.workflow.WorkflowStarter;
import net.neptech.repository.WorkflowRepo;
import net.neptech.service.FlowableService;
import net.neptech.service.FormService;
import net.neptech.service.WorkflowService;
import net.neptech.service.StarterService;
import net.neptech.util.JsonUtil;
import net.neptech.util.NodeUtil;
import net.neptech.utils.SecurityUtils;
import net.neptech.model.vo.FormVO;
import net.neptech.model.vo.WorkflowVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author Saya
 * @Date 2025/8/18 16:54
 * @Description 主工作流业务
 **/
@Service
@Slf4j
public class WorkflowServiceImpl extends ServiceImpl<WorkflowMapper,Workflow> implements WorkflowService {
    @Autowired
    private WorkflowRepo workflowRepo;

    @Autowired
    private StarterService starterService;

    @Autowired
    private FlowableService flowableService;

    @Autowired
    private FormService formService;

    /**
     * @Author Saya
     * @Date 2025/8/19 12:00
     * @Description 根据UniqueId查询该工作流的左右版本列表
     * @Params [uniqueId]
     * @Return net.neptech.model.vo.WorkflowVO
     **/
    @Override
    public WorkflowVO getListByUniqueId(String uniqueId) {
        List<Workflow> workflowList = workflowRepo.findByUniqueId(uniqueId).stream().filter(workflow -> workflow.getHidden().equals(false)).sorted(Comparator.comparing(Workflow::getFlowId)).toList();
        return (WorkflowVO) BeanUtil.copyToList(workflowList, WorkflowVO.class);
    }

    /**
     * @Author Saya
     * @Date 2025/8/19 11:59
     * @Description 设置为主流程
     * @Params [flowId]
     * @Return void
     **/
    @Override
    public void setMainWorkflow(String flowId) {
        Workflow wf = this.getByFlowId(flowId);
        //先停用了
        List<Workflow> wfList = workflowRepo.findByUniqueId(wf.getUniqueId()).stream().toList();
        wfList.forEach(workflow -> workflow.setStop(true));
        workflowRepo.saveAll(wfList);
        //设置为主流程
        wf.setStop(false);
        workflowRepo.save(wf);
    }

    /**
     * @Author Saya
     * @Date 2025/8/19 11:59
     * @Description 获取工作流的详细数据
     * @Params [flowId]
     * @Return net.neptech.model.vo.WorkflowVO
     **/
    @Override
    public WorkflowVO getDetail(String flowId) {
        WorkflowVO workflowVO = this.getWorkflowVO(flowId);
        if (workflowVO == null) {
            throw new RuntimeException("流程不存在");
        }
        return workflowVO;
    }

    /**
     * @Author Saya
     * @Date 2025/8/20 10:24
     * @Description 根据flowId获取VO对象
     * @Params [flowId]
     * @Return net.neptech.model.vo.WorkflowVO
     **/
    private WorkflowVO getWorkflowVO(String flowId) {
        Workflow wf = workflowRepo.findById(flowId).orElse(null);
        if (wf == null) return null;
        //"清洗"JSON
        String formConfig = wf.getFormConfig();
        List<FormVO> FormVOList = JsonUtil.parseArray(formConfig, FormVO.class);
        wf.setFormConfig(JsonUtil.toJSONString(FormVOList));
        WorkflowVO workflowVO = BeanUtil.copyProperties(wf, WorkflowVO.class);
        //查询并添加发起人rangeList
        List<WorkflowStarter> workflowStarterList = starterService.getByFlowId(wf.getFlowId());
        List<NodeUser> rangeList = new ArrayList<>();
        for (WorkflowStarter workflowStarter : workflowStarterList) {
            NodeUser nodeUser = JsonUtil.parseObject(workflowStarter.getData(), NodeUser.class);
            rangeList.add(nodeUser);
        }
        workflowVO.setRangeList(rangeList);
        return workflowVO;
    }

    /**
     * @Author Saya
     * @Date 2025/8/20 10:34
     * @Description 抽离的工作流查询方法（不包含已删除）
     * @Params [flowId]
     * @Return net.neptech.model.workflow.Workflow
     **/
    @Override
    public Workflow getByFlowId(String flowId) {
        Workflow wf = workflowRepo.findById(flowId).filter(w -> w.getDeleted().equals(false)).orElse(null);
        if (wf == null) {
            throw new RuntimeException("该工作流不存在");
        }
        return wf;
    }

    /**
     * @Author Saya
     * @Date 2025/8/20 10:35
     * @Description 查询工作流（包含已删除）
     * @Params [flowId]
     * @Return net.neptech.model.workflow.Workflow
     **/
    @Override
    public Workflow getByFlowIdContainDeleted(String flowId) {
        return workflowRepo.findById(flowId).orElse(null);
    }

    /**
     * @Author Saya
     * @Date 2025/8/20 11:04
     * @Description 根据唯一id查询工作流
     * @Params [uniqueId]
     * @Return net.neptech.model.workflow.Workflow
     **/
    @Override
    public List<Workflow> getByUniqueId(String uniqueId) {
        return workflowRepo.findByUniqueId(uniqueId).stream().filter(w -> w.getDeleted().equals(false)).toList();
    }

    /**
     * @Author Saya
     * @Date 2025/8/20 11:08
     * @Description 更新工作流
     * @Params [Workflow]
     * @Return void
     **/
    @Override
    public void updateByFlowId(Workflow Workflow) {
        workflowRepo.save(Workflow);
    }

    /**
     * @Author Saya
     * @Date 2025/8/20 11:09
     * @Description 停用工作流
     * @Params [flowId]
     * @Return void
     **/
    @Override
    public void stop(String flowId) {
        Workflow wf = workflowRepo.findById(flowId).orElse(null);
        if (wf == null) throw new RuntimeException("工作流不存在");
        wf.setStop(true);
        workflowRepo.save(wf);
    }

    /**
     * @Author Saya
     * @Date 2025/8/20 11:09
     * @Description 创建工作流
     * @Params [workflowVO]
     * @Return void
     **/
    @Transactional
    @Override
    public void create(WorkflowVO workflowVO) {
        System.out.println(workflowVO);
        String paramUniqueId = workflowVO.getUniqueId();
        //唯一性确认
        {
            String name = workflowVO.getFlowName();
            List<Workflow> workflowList = workflowRepo.findByFlowName(name).stream().filter(w -> w.getHidden().equals(false) && w.getDeleted().equals(false)).sorted(Comparator.comparing(Workflow::getFlowId)).toList();
            if (!workflowVO.getFlowId().isBlank()) {
                Workflow workflow = getByFlowId(workflowVO.getFlowId());
                if (workflow == null || workflow.getHidden())
                    throw new RuntimeException("流程不存在，请退出流程重新打开编辑");
                String uniqueId = workflow.getUniqueId();
                if (!StrUtil.equals(uniqueId, paramUniqueId)) throw new RuntimeException("流程id不匹配");
                if (workflow.getStop()) {
                    //已停用了 但是其他的未停用 那该流程不能修改
                    long count = getByUniqueId(uniqueId).stream().filter(w1 -> w1.getStop().equals(false) && w1.getHidden().equals(false)).count();
                    if (count > 0) throw new RuntimeException("流程状态已变更，请退出流程重新打开编辑");
                }
                long count = workflowList.stream().filter(w3 -> !StrUtil.equals(w3.getUniqueId(), paramUniqueId)).count();
                if (count > 0) throw new RuntimeException("流程名字已存在，不能重复");
            } else {
                if (!workflowList.isEmpty()) throw new RuntimeException("流程名字已存在，不能重复");
                //判断uniqueId
                boolean empty = getByUniqueId(paramUniqueId).isEmpty();
                if (!empty) throw new RuntimeException("流程id已存在");
            }
        }
        String workflowJson = workflowVO.getFlow();
        System.out.println(workflowJson);
        Node node = JsonUtil.parseObject(workflowJson, Node.class);
        if (node == null) throw new RuntimeException("NODE对象转换错误");
        NodeUtil.handleParentId(node, null);
        //处理发起人节点
        NodeUtil.handleStarterForm((RootNode) node, JsonUtil.parseArray(workflowVO.getFormConfig(), FormVO.class));
        //处理审批节点表单
        NodeUtil.handleApproveForm(node, JsonUtil.parseArray(workflowVO.getFormConfig(), FormVO.class));
        //处理抄送节点表单
        NodeUtil.handleCopyForm(node, JsonUtil.parseArray(workflowVO.getFormConfig(), FormVO.class));
        NodeUtil.handleApprove(node);
        NodeUtil.handEmptyNode(node);

        //调用flowable创建流程
        CreateFlowDto createFlowDto = new CreateFlowDto();
        createFlowDto.setUserId(SecurityUtils.getUserId());
        createFlowDto.setNode(JsonUtil.parseObject(JsonUtil.toJSONString(node), Node.class));
        createFlowDto.setProcessName(workflowVO.getFlowName());
        String flowId = flowableService.create(createFlowDto);

        NodeUser nodeUser = JsonUtil.parseArray(workflowVO.getAdmin(), NodeUser.class).get(0);

        if (!workflowVO.getFlowId().isBlank()) {
            Workflow oldWorkflow = this.getByFlowId(workflowVO.getFlowId());
            if (workflowVO.getPublish()) {
                //如果是发布
                this.stop(workflowVO.getFlowId());
            }
            //修改所有的管理员
            List<Workflow> workflowList = getByUniqueId(workflowVO.getUniqueId());
            workflowList.forEach(workflow -> workflow.setAdminId(nodeUser.getUserId()));
            workflowRepo.saveAll(workflowList);
        }
        //发起人范围
        List<NodeUser> nodeUserList = workflowVO.getRangeList();
        StringBuilder stringBuilder = new StringBuilder();
        //拼装发起人JSONStr
        if (CollUtil.isNotEmpty(nodeUserList)) {
            int index = 0;
            for (NodeUser user : nodeUserList) {
                if (index > 0) {
                    stringBuilder.append(",");
                }
                stringBuilder.append(user.getName());
                index++;
                if (index > 5) {
                    break;
                }
            }
        }
        int version = 1;
        if (!paramUniqueId.isBlank()) {
            List<Workflow> workflowList = getByUniqueId(paramUniqueId).stream().sorted(Comparator.comparing(Workflow::getVersion).reversed()).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(workflowList)) {
                version = workflowList.get(0).getVersion() + 1;
            }
        }

        Workflow p = new Workflow();
        p.setFlowId(flowId);
        p.setFlowName(workflowVO.getFlowName());
        p.setIcon(workflowVO.getIcon());

        p.setGroupId(workflowVO.getGroupId());
        p.setFormConfig(workflowVO.getFormConfig());
        p.setFormContent(workflowVO.getFormContent());
        p.setFlow(JsonUtil.toJSONString(node));
        p.setRemark(workflowVO.getRemark());
        p.setSort(0);
        p.setHidden(false);
        p.setStop(true);
        if (workflowVO.getPublish()) {
            p.setStop(false);
        }
        p.setAdminId(nodeUser.getUserId());
        p.setUniqueId(paramUniqueId);
        p.setAdmin(workflowVO.getAdmin());
        p.setRangeShow(stringBuilder.toString());
        p.setVersion(version);

        workflowRepo.save(p);
        //保存到主表（应该不需要）
//        WorkflowMain workflowMain = BeanUtil.copyProperties(p, WorkflowMain.class, "id");
//        boolean mainExist = WorkflowMainService.lambdaQuery().eq(WorkflowMain::getUniqueId, paramUniqueId).exists();
//        if (!mainExist) {
//            workflowMainService.save(WorkflowMain);
//        } else if (workflowVO.getPublish()) {
//            workflowMainService.lambdaUpdate().eq(WorkflowMain::getUniqueId, paramUniqueId).eq(WorkflowMain::getTenantId, TenantUtil.get()).update(WorkflowMain);
//        }
        //保存节点人员范围
        if (CollUtil.isNotEmpty(nodeUserList)) {
            for (NodeUser nodeUserDto : nodeUserList) {
                WorkflowStarter workflowStarter = new WorkflowStarter();
                workflowStarter.setContainChildrenDept(nodeUserDto.getContainChildrenDept());
                workflowStarter.setProcessId(p.getFlowId());
                workflowStarter.setFlowId(p.getFlowId());
                workflowStarter.setStarterId((nodeUserDto.getUserId().toString()));
                workflowStarter.setType(nodeUserDto.getType());
                workflowStarter.setData(JsonUtil.toJSONString(nodeUserDto));
                starterService.save(workflowStarter);
            }
        }
        //保存工作流表单
        List<FormVO> FormVOS = JsonUtil.parseArray(workflowVO.getFormConfig(), FormVO.class);
        for (FormVO FormVO : FormVOS) {
            WorkflowForm workflowForm = new WorkflowForm();
            workflowForm.setUniqueId(p.getUniqueId());
            workflowForm.setFlowId(p.getFlowId());
            workflowForm.setFormName(FormVO.getFormName());
            workflowForm.setFormId(FormVO.getFormId());
            workflowForm.setFormType(FormVO.getFormType());
            workflowForm.setProps(JsonUtil.toJSONString(FormVO.getProps()));
            formService.save(workflowForm);
        }
    }

    /**
     * 编辑表单
     */
    @Override
    public void update(String flowId, String type, String groupId) {
        Workflow workflow = new Workflow();
        workflow.setFlowId(flowId);
        workflow.setStop("stop".equals(type));
        workflow.setHidden("delete".equals(type));
        workflow.setGroupId(groupId);
        workflowRepo.save(workflow);
    }

    /**
     * 查询所有关联的流程id
     */
    @Override
    public List<String> getAllRelatedFlowId(List<String> flowIdList) {
        List<Workflow> list = workflowRepo.findAllById(flowIdList);
        Set<String> uniqueIdSet = list.stream().map(Workflow::getUniqueId).collect(Collectors.toSet());
        List<Workflow> workflowList = workflowRepo.findByUniqueIdIn(uniqueIdSet);
        return workflowList.stream().map(Workflow::getFlowId).collect(Collectors.toList());
    }

    /**
     * 清理数据(逻辑删除)
     */
    @Override
    public void clearWorkflow(String uniqueId) {
        List<Workflow> wlist = getByUniqueId(uniqueId);
        wlist.forEach(workflow -> workflow.setDeleted(true));
        workflowRepo.saveAll(wlist);
    }
}